﻿using Kaskelot.Services.Model;
using Stockholm.SOA.Kaskelot.WCF.Core;
using Stockholm.SOA.Kaskelot.WCF.ServiceImplementation.NotificationService;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.ServiceModel;
using System.Web;

namespace Stockholm.SOA.Kaskelot.WCF.ServiceImplementation.Repositories
{
	internal class NotificationRepository : IDisposable
	{
		#region Constructor & Dispose
		private NotificationService.NotificationServiceClient client;

		private KaskelotEntities context;
		public NotificationRepository()
		{
			this.context = new KaskelotEntities();

			client = new NotificationServiceClient("WSHttpBinding_INotificationService");
			client.Open();
		}

		public void Dispose()
		{
			if (client.State == CommunicationState.Opened)
				client.Close();
			else if (client.State == CommunicationState.Faulted)
				client.Abort();

			this.context.Dispose();
		}
		#endregion

		#region Helpers
		private string EnsureMobTelNr(string mobTelNr)
		{
			if (!string.IsNullOrEmpty(mobTelNr))
			{
				var allowedChars = "+0123456789";
				string s = mobTelNr.Replace(" ", "");
				s = new string(s.Where(c => allowedChars.Contains(c)).ToArray());

				if (s.StartsWith("0"))
				{
					s = new string(s.Skip(1).ToArray());
					s = "+46" + s;

					return s;
				}
				else if (s.StartsWith("+"))
				{
					return s;
				}
			}

			return string.Empty;
		}

		internal string FormatBody(string blankettNamn, DataContracts.FaltData[] faltData)
		{
			string s = "Inskickat meddelande via formuläret '" + blankettNamn + "'\n\n";
			foreach (DataContracts.FaltData fd in faltData)
			{
                if (fd.Falt != null && fd.Data != null)
				    s += fd.Falt.Namn + ":\n" + fd.Data + "\n\n";
			}

			s += "\n";
			return s;
		}
		#endregion

		#region Email
		internal DataContracts.NotifieringsResultat SendEmail(string blankettNamn, DataContracts.FaltData[] faltData)
		{
			string mottagare = ConfigurationManager.AppSettings["ExternEpostMottagare"];
			if(string.IsNullOrEmpty(mottagare))
				throw new ApplicationException("AppSetting 'ExternEpostMottagare' not found.");

			string[] to = new string[] { mottagare };
			string from = mottagare;
			string reply = mottagare;
			string fromDisplay = "Kaskelot extern";
            string subject = "Inget ämne";
			string body = FormatBody(blankettNamn, faltData);

            try
            {
                var subj = faltData.FirstOrDefault(x => x.Falt.Namn.ToLower().Contains("ämne") || x.Falt.Namn.ToLower().Contains("ärende"));
                if (subj != null)
                    subject = subj.Data;
            }
            catch (Exception ex)
            {
                throw new ApplicationException("Error finding subject field. " + ex.ToString());
            }

            try
            {
                var epost = faltData.FirstOrDefault(x => x.Falt.Typ == DataContracts.FaltTyp.Epostadress);
                if (epost != null)
                {
                    from = epost.Data;
                    reply = epost.Data;
                }
            }
            catch (Exception ex)
            {
                throw new ApplicationException("Error finding epost field. " + ex.ToString());
            }

			DataContracts.NotifieringsResultat svar = SendEmail(to, null, null, subject, body, from, fromDisplay, reply);
			if(svar.Fel == false && !string.IsNullOrEmpty(from))
				svar = SendEmail(new string[] { from }, null, null, "Ditt ärende har skickats", "Nedan är en kopia på meddelandet som skickades:\n\n----\n\n" + body, mottagare, "Valnämnden", mottagare);

			return svar;
		}

		internal DataContracts.NotifieringsResultat SendEmail(string[] to, string[] cc, string[] bcc, string subject, string body, string from, string fromDisplay, string reply, bool html = false)
		{
			NotificationService.EmailMessage msg = new NotificationService.EmailMessage();
			
			msg.To = to;
			msg.Cc = cc;
			msg.Bcc = bcc;
			
			msg.Subject = subject;
			msg.MessageBody = body;
			
			msg.From = from;
			msg.FromDisplayName = fromDisplay;
			msg.ReplyTo = reply;

			msg.IsBodyHtml = html;

			return SendEmail(msg);
		}

		internal DataContracts.NotifieringsResultat SendEmail(NotificationService.EmailMessage msg)
		{
			DataContracts.NotifieringsResultat svar = new DataContracts.NotifieringsResultat()
			{ 
				Fel = false,
				FelKod = string.Empty,
				Meddelande = string.Empty
			};

			try
			{
				client.SendEmailMessage(msg);
			}
			catch (FaultException fe)
			{
				Logger.LogError(this, Constants.LayerNames.Services, "SendEmail", "SendEmailMessage failed.", fe);
				svar.Meddelande = fe.Message;
                svar.FelKod =  fe.Code != null ? fe.Code.Name : "FaultException";
				svar.Fel = true;
			}
			catch (Exception ex)
			{
				svar.Meddelande = ex.Message;
				svar.FelKod = "Exception";
				svar.Fel = true;
			}

			return svar;
		}
		#endregion

		#region SMS
		internal void SendSMS(string receiver, string content)
		{
			SendSMS(new string[] { receiver }, content);
		}

		internal DataContracts.NotifieringsResultat SendSMS(IEnumerable<string> receivers, string content)
		{
			#region Ensure parameters
			if (content.Length > Constants.SMSMaxLength)
			{
				Logger.LogWarning(this, Constants.LayerNames.Services, "SendSMS", "SMS-meddelande för långt. Ignorerar överskridande tecken.");
				content = new string(content.Take(Constants.SMSMaxLength).ToArray()); // Ensure maxlength
			}

			receivers = receivers.Select(x => EnsureMobTelNr(x)).ToList();
			NotificationService.Recipients rec = new NotificationService.Recipients();
			rec.Recipient = receivers.ToArray();
			#endregion

			NotificationService.SMSRequest request = new NotificationService.SMSRequest();

			request.User = ConfigurationManager.AppSettings["SMSUser"];
			request.Password = ConfigurationManager.AppSettings["SMSPass"];
			request.Action = ConfigurationManager.AppSettings["SMSAction"];

			request.UseFlash = "false";
			request.StatusControl = "false";

			request.Message = content;
			request.Recipients = rec;

			return SendSMS(request);
		}

		internal DataContracts.NotifieringsResultat SendSMS(NotificationService.SMSRequest msg)
		{
			DataContracts.NotifieringsResultat svar = new DataContracts.NotifieringsResultat()
			{
				Fel = false,
				FelKod = string.Empty,
				Meddelande = string.Empty
			};

			try
			{
				Logger.LogInformation(this, Constants.LayerNames.Services, "SendSMS", "Attempting SendSMSRequest.");
				client.SendSMSRequest(msg);
			}
			catch (FaultException fe)
			{
				svar.Meddelande = fe.Message;
				svar.FelKod = fe.Code.Name;
				svar.Fel = true;
			}
			catch (Exception ex)
			{
				svar.Meddelande = ex.Message;
				svar.FelKod = string.Empty;
				svar.Fel = true;
			}

			return svar;
		}
		#endregion
	}
}
